<?php
/*
 * [posttype_builder id='posttype_builder' label='Custom Post Type' usercap='edit_plugins' tableclasses='table-bordered,table-striped,table-hover,table-condensed']
 *
 */

namespace WebApper\Shortcode;

class PosttypeBuilder extends \WebApper\Shortcode {
	
    /**
     * Define shortcode properties
     *
     */
	protected $shortcode = 'posttype_builder';
	protected $defaults = array(
		'id' => 'posttype_builder',		// The unique ID to use for the shortcode. Default: none. Required.
		'usercap' => 'edit_plugins',	// The minimum user capability required to access the Post Type Builder. OPTIONS: 'read', 'edit_posts', 'edit_others_posts', 'edit_users', 'edit_pages', 'edit_plugins'. Default 'edit_plugins'.
		'label' => 'Post Type',			// The cutom post type label to display. Default: 'Post Type'.
		'tableclasses' => 'table-bordered,table-striped,table-hover,table-condensed',  // Adjust how the DataTable will display. Default: 'table-bordered,table-striped,table-hover,table-condensed'.
	);

    /**
     * Initialize the Shortcode Class
     *
     */
    public function __construct() {
       add_shortcode( $this->shortcode, array($this, 'shortcode') );
	   add_action( 'wp_ajax_web_apper' . $this->shortcode, array($this, 'sendAjaxResponse') );
	   add_action( 'init', array($this, 'web_apper_posttype_init') );
	}

    /**
     * Handles the [posttype_builder] shortcode
     *
     * @param array $atts
     */
    public function shortcode( $atts ) {

		// Get shortcode attributes
			extract( shortcode_atts( $this->defaults, $atts ) );

		// Ouput datatable HTML & Javascript
			?>
            <hr />
            <div class="alert alert-info fade in">
                <button type="button" class="close" data-dismiss="alert">&times;</button>
                <strong>How To!</strong> Use this tool to create 'Post Types' in WordPress. This is the center for creating different types of records. Post types are used as a type of record like a lead, contact, listing or client. Once created, new records(or posts) of that post type can be created and managed with a shortcode. Rows are selectable. Click on the add, edit, or delete button to get started.
            </div>
			<table id="<?php echo $id; ?>_datatable" class="table <?php echo str_replace(",", " ", $tableclasses); ?>">
				<thead>
					<tr>
						<th>Name</th>
						<th>Singular Name</th>
						<th>ID/Slug</th>
						<th>Exclude from search</th>
						<th>Archive</th>
						<th>Revisions</th>
						<th>Show in WP Admin menu</th>
						<th>WP Admin menu position</th>
						<th>Show in admin bar</th>
						<th>Show in nav menus</th>
					</tr>
				</thead>
				<tbody>
					<?php
					$posttypes  = get_option( 'web_apper_cpts', array() );  // Get CPTs array from site options
					foreach ( $posttypes as $posttype_id => $posttype ) :
						echo '<tr>',
								 '<td>', $posttype['name'], '</td>',
								 '<td>', $posttype['name_singular'], '</td>',
								 '<td>', $posttype_id, '</td>',
								 '<td>', $posttype['exclude_from_search'], '</td>',
								 '<td>', $posttype['has_archive'], '</td>',
								 '<td>', $posttype['revisions'], '</td>',
								 '<td>', $posttype['show_ui'], '</td>',
								 '<td>', $posttype['menu_position'], '</td>',
								 '<td>', $posttype['show_in_admin_bar'], '</td>',
								 '<td>', $posttype['show_in_nav_menus'], '</td>',
							 '</tr>';
					endforeach;
					?>
				</tbody>
			</table>

			<script type="text/javascript">
				// Store Commonly manipulated DOM nodes as objects
				nForm = jQuery('#<?php echo $id; ?>');
				nFormTask = jQuery('input[name="web_apper_task"]', nForm);
				nModal = jQuery('.modal', nForm);
				nModalHeader = jQuery('.modal-header h3', nModal)
				nModalBody = jQuery('.modal-body', nModal);
				nModalClose = jQuery('.modal-footer [data-dismiss="modal"]', nModal)
				nModalSaveBtn = jQuery('.modal-footer #save', nModal)
				nModalUpdateBtn = jQuery('.modal-footer #update', nModal)
				nModalDeleteBtn = jQuery('.modal-footer #delete', nModal)
				nModalElements = jQuery('.modal-body>*', nModal);
				nDeleteWarning = jQuery('#deleteWarning', nModal);
				nTable = jQuery('#<?php echo $id; ?>_datatable');

				jQuery(document).ready(function($) {
					// Initialize dataTable
					oTable = $(nTable).dataTable({
						<?php
							// Build the sDom parameter for dataTables
							global $template;
							if ( stristr($template, 'fullwidth') ) :
								$spanA = 6; $spanB = 6;
							else :
								$spanA = 4; $spanB = 5;
							endif;
							echo "'sDom': \"<'row'<'span".$spanA."'EC><'span".$spanB."'fl>r>t<'row'<'span".$spanA."'i><'span".$spanB."'p>>\",\n";
						?>
						'sPaginationType': 'bootstrap',
						'oLanguage': {
							'sLengthMenu': 'records per page <select>'+
							'<option value="10">10</option>'+
							'<option value="20">20</option>'+
							'<option value="30">30</option>'+
							'<option value="40">40</option>'+
							'<option value="50">50</option>'+
							'<option value="100">100</option>'+
							'</select>'
						},
						'aoColumnDefs': [ { 'bVisible': false, 'aTargets': [ 1, 2 ] } ],
						'oColVis': {
							'buttonText': 'Columns',
							'bRestore': true,
							'sAlign': 'left',
							'sSize': 'css',
						},
					});

				});
				// Handle response from ajax post
				function parseResponse<?php echo $id; ?>(response) {
					var result = jQuery.parseJSON(response);  // Parse response
					if ( result.success ) {  // If ajax returns a successful save
						if ( result.task == 'add' ) {  // If we added a row
							var formValues = nForm.getFormValues();  // Get array of form values
							oTable.fnAddDataAndDisplay(formValues);  // Add row to table
							nForm.clearForm();  // Clear form values
						} else if ( result.task == 'update' ) {  // If we updated a row
							var rowPosition = oTable.fnGetPosition( jQuery('tr.row_selected')[0] );  // Get the position of the currently selected row
							var formValues = nForm.getFormValues();  // Get array of form values
							oTable.fnUpdate( formValues, rowPosition ); // Update the dataTable row
						} else if ( result.task == 'delete' ) {  // If we deleted a row
							nDeleteWarning.css('display', 'none');  // Hide the delete warning
							nModalDeleteBtn.css('display', 'none');  // Hide the modal submit button
							var rowPosition = oTable.fnGetPosition( jQuery('tr.row_selected')[0] );  // Get the position of the currently selected row
							oTable.fnDeleteRow( rowPosition );
						}
					}
					resetModalButtons();
					nModalBody.prepend(result.htmlalert);  // Show and alert
				}
			</script>
            <?php

		// Configure form settings
			$this->config_form( $atts );  // Check if user has proper privileges

		// Build the form
			$form = new \PFBC\Form($id);
			$form->configure( $this->formConfig );
			$form->addElement(new \PFBC\Element\Hidden('web_apper_form', $id));
			$form->addElement(new \PFBC\Element\Hidden('web_apper_nonce', wp_create_nonce( 'WebApperAwesomeness!87' )));
			$form->addElement(new \PFBC\Element\Hidden('action', 'web_apper' . $this->shortcode));
			$form->addElement(new \PFBC\Element\Hidden('web_apper_task', 'add'));
			// Form Modal header
			$form->addElement(new \PFBC\Element\ModalHeading($label));
			$form->addElement(new \PFBC\Element\HTML('<div id="deleteWarning"><span class="label label-important pull-left">Delete ' . $label . '</span><p>&nbsp;You are about to delete a ' . $label . '. Are you sure you want to do this?</p></div>'));
			// Form Modal body
			$form->addElement(new \PFBC\Element\Textbox('Name:', 'name', array(
				'required' => 1,
				'longDesc' => 'A plural name for the custom post type. e.g., Oppertunities, not Oppertunity.'
			)));
			$form->addElement(new \PFBC\Element\Textbox('Singuar Name:', 'name_singular', array(
				'required' => 1,
				'longDesc' => 'A singular name for the custom post type. e.g., Lead, not Leads.'
			)));
			$form->addElement(new \PFBC\Element\Textbox('ID:', 'id_slug', array(
				'required' => 1,
				'placeholder' => 'posttype-id',
				'shortDesc' => 'A unique ID for the custom post type',
				'longDesc' => 'Must be alphanumeric: contain only lowercase letters, numbers, underscores(_) and/or hyphens(-). Note: will be used as the custom post type slug. Cannot be changed once saved.'
			)));
			$form->addElement(new \PFBC\Element\YesNo('Exclude from search:', 'exclude_from_search', array(
				'required' => 1,
				'longDesc' => 'Whether to exclude posts with this post type from front end search results.'
			)));
			$form->addElement(new \PFBC\Element\YesNo('Archive:', 'has_archive', array(
				'required' => 1,
				'longDesc' => 'Whether to enable post type archives.'
			)));
			$form->addElement(new \PFBC\Element\YesNo('Revisions:', 'revisions', array(
				'required' => 1,
				'longDesc' => 'Whether to enable post revisions.'
			)));
			$form->addElement(new \PFBC\Element\YesNo('Show in WP Admin menu:', 'show_ui', array(
				'required' => 1,
				'longDesc' => 'Whether to make this post type available in the WP Admin menu.'
			)));
			$form->addElement(new \PFBC\Element\Number('WP admin menu position:', 'menu_position', array(
				'longDesc' => 'The position in the menu order the post type should appear, 5 is below "Posts".'
			)));
			$form->addElement(new \PFBC\Element\YesNo('Show in admin bar:', 'show_in_admin_bar', array(
				'required' => 1,
				'longDesc' => 'Whether to make this post type available in the WordPress admin bar.'
			)));
			$form->addElement(new \PFBC\Element\YesNo('Show in nav menus:', 'show_in_nav_menus', array(
				'required' => 1,
				'longDesc' => 'Whether post_type is available for selection in navigation menus.'
			)));
			// Form Modal footer
			$form->addElement(new \PFBC\Element\Button('Save', 'submit', array(
				'id' => 'save',
				'data-loading-text' => 'Saving...'
			)));
			$form->addElement(new \PFBC\Element\Button('Update', 'submit', array(
				'id' => 'update',
				'data-loading-text' => 'Updating...'
			)));
			$form->addElement(new \PFBC\Element\Button('Delete', 'submit', array(
				'id' => 'delete',
				'class' => 'btn btn-danger',
				'data-loading-text' => 'Deleting...'
			)));
            $form->render();  // Output the form

	}

    /**
     * Add new record
     *
     * @since 1.0
     */
	public function add_record() {
		$posttype_id = $_POST['id_slug'];
		$posttype = array(
			'name_singular' => $_POST['name_singular'],
			'name' => $_POST['name'],
			'exclude_from_search' => $_POST['exclude_from_search'],
			'has_archive' => $_POST['has_archive'],
			'revisions' => $_POST['revisions'],
			'show_ui' => $_POST['show_ui'],
			'menu_position' => $_POST['menu_position'],
			'show_in_admin_bar' => $_POST['show_in_admin_bar'],
			'show_in_nav_menus' => $_POST['show_in_nav_menus'],
		);
		// Get current CPTs array, add new CPT, update to DB, echo result
		$current_posttypes  = get_option( 'web_apper_cpts', array() );
		$current_posttypes[$posttype_id] = $posttype;
		if ( update_option( 'web_apper_cpts', $current_posttypes ) ) :		
			return $this->sendResponse( 'Custom post type saved.', 'alert-success', 'Hurray!', true );  // Send Response
			// Register new CPT and flush permalinks
			$this->web_apper_posttype_init();
			flush_rewrite_rules();
		else :
			return $this->sendResponse( 'There was a problem saving the custom post type. Please Try again.', 'alert-error', 'Oh snap!', false );  // Send Response
		endif;
	}

    /**
     * Update a record
     *
     * @since 1.0
     */
	public function update_record() {
		// Get the ID of the CPT to update
		$posttype_id = $_POST['id_slug'];
		$posttype = array(
			'name_singular' => $_POST['name_singular'],
			'name' => $_POST['name'],
			'exclude_from_search' => $_POST['exclude_from_search'],
			'has_archive' => $_POST['has_archive'],
			'revisions' => $_POST['revisions'],
			'show_ui' => $_POST['show_ui'],
			'menu_position' => $_POST['menu_position'],
			'show_in_admin_bar' => $_POST['show_in_admin_bar'],
			'show_in_nav_menus' => $_POST['show_in_nav_menus'],
		);
		// Get current CPTs array, update CPT, update to DB, echo result
		$current_posttypes  = get_option( 'web_apper_cpts', array() );
		$current_posttypes[$posttype_id] = $posttype;
		if ( update_option( 'web_apper_cpts', $current_posttypes ) ) :		
			return $this->sendResponse( 'Custom post type updated.', 'alert-success', 'Hurray!', true );  // Send Response
			// Register new CPT and flush permalinks
			web_apper_cpt_init();
			flush_rewrite_rules();
		else :
			return $this->sendResponse( 'Custom post type was not updated. Make sure you made a change before updating.', 'alert-error', 'Oh snap!', false );  // Send Response
		endif;
	}

    /**
     * Delete a record
     *
     * @since 1.0
     */
	public function delete_record() {
		// Get the ID of the CPT to delete
		$posttype_id = $_POST['id_slug'];
		// Get current CPTs array, add new CPT, update to DB, echo result
		$current_posttypes  = get_option( 'web_apper_cpts', array() );
		unset($current_posttypes[$posttype_id]);
		if ( update_option( 'web_apper_cpts', $current_posttypes ) ) :		
			return $this->sendResponse( 'Custom post type deleted.', 'alert-success', 'Hurray!', true );  // Send Response
			// Register CPTs and flush permalinks
			$this->web_apper_cpt_init();
			flush_rewrite_rules();
		else :
			return $this->sendResponse( 'There was a problem deleting the custom post type. Please Try again.', 'alert-error', 'Oh snap!', false );  // Send Response
		endif;
	}

    /**
     * Registers custom post types
     *
     * @since 1.0
     */
	public function web_apper_posttype_init() {
		// Get CPTs array from site options
		$web_apper_cpts  = get_option( 'web_apper_cpts', array() );
		// Set CPT args & register
		foreach ( $web_apper_cpts as $cpt_id => $cpt ) :
			$labels = array(
				'name' => $cpt['name'],
				'singular_name' => $cpt['name_singular'],
				'add_new' => 'Add New',
				'add_new_item' => 'Add New ' . $cpt['name_singular'],
				'edit_item' => 'Edit ' . $cpt['name_singular'],
				'new_item' => 'New ' . $cpt['name_singular'],
				'all_items' => 'All ' . $cpt['name'],
				'view_item' => 'View ' . $cpt['name_singular'],
				'search_items' => 'Search ' . $cpt['name'],
				'not_found' =>  'No ' . strtolower( $cpt['name'] ) . ' found',
				'not_found_in_trash' => 'No ' . strtolower( $cpt['name'] ) . ' found in Trash', 
				'menu_name' => $cpt['name']
			);
			$args = array(
				'labels' => $labels,
				'public' => true,
				'exclude_from_search' => $this->textToBool($cpt['exclude_from_search']),
				'show_ui' => $this->textToBool($cpt['show_ui']), 
				'menu_position' =>  intval( $cpt['menu_position'] ),
				'show_in_admin_bar' =>  $this->textToBool($cpt['show_in_admin_bar']),
				'show_in_nav_menus' =>  $this->textToBool($cpt['show_in_nav_menus']),
				'rewrite' => array( 'slug' => $cpt_id ),
				'has_archive' => $this->textToBool($cpt['has_archive']), 
				'supports' => array( 'title', 'author', 'custom-fields' )
			); 
			if ( $this->textToBool($cpt['revisions']) ) : 
				$args['supports'][] = 'revisions';
			endif;
			register_post_type( $cpt_id, $args );
		endforeach;
	}

}

$initialize = new PosttypeBuilder(); 

?>